package com.fla.puzzle;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

import com.danikula.aibolit.Aibolit;
import com.danikula.aibolit.ServicesResolver;
import com.fla.puzzle.utils.Utils;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.download.ImageDownloader;

import android.app.Application;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.preference.PreferenceManager;

/**
 * PuzzleBody application class.
 * <p>
 * Used to keep global application data and provides access to application services.
 * </p>
 */
public class PuzzleApplication extends Application {
    private static final String SOUND_ENABLED_KEY = "SOUND_ENABLED_KEY";
    
    private static PuzzleApplication instance;

    private PackManager packManager;
    private GameModelManager gameModelManager;
    private PackDataProvider packDataProvider;
    private CompletedManager completedManager;
    
    private Typeface headerTypeface;
    
    private SharedPreferences preferences;

    @Override
    public void onCreate() {
        super.onCreate();

        instance = this;
        
        preferences = PreferenceManager.getDefaultSharedPreferences(this);

        Aibolit.addServicesResolver(new ServicesResolverImpl());
        
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            .defaultDisplayImageOptions(new DisplayImageOptions.Builder().cacheInMemory().build())
            .imageDownloader(new CustomDownloader())
//            .enableLogging()
            .build();
    
        ImageLoader.getInstance().init(config);
    }

    private class CustomDownloader extends ImageDownloader {
        @Override
        protected InputStream getStreamFromOtherSource(URI uri) throws IOException {
            return getPackDataProvider().loadInputStream(Utils.fromURI(uri));
        }

        @Override
        protected InputStream getStreamFromNetwork(URI imageUri) throws IOException {
            return null;
        }
    }

    /**
     * Returns an application.
     * 
     * @return PuzzleBody Application singleton.
     */
    public static PuzzleApplication getInstance() {
        if (instance == null) {
            throw new IllegalStateException("Application isn't initialized yet!");
        }
        return instance;
    }

    public Typeface getHeaderTypeface() {
        if (headerTypeface == null) {
            headerTypeface = Typeface.createFromAsset(getAssets(), "fonts/AG_Helvetica Regular.ttf");
        }
        return headerTypeface;
    }

    public CompletedManager getCompletedManager() {
        return completedManager == null ? completedManager = new CompletedManager(
            preferences) : completedManager;
    }

    /**
     * Returns pack manager that manages available game packages
     * 
     * @return {@link PackManager}
     */
    public PackManager getPackManager() {
        return packManager == null ? packManager = new PackManager(getPackDataProvider()) : packManager;
    }

    /**
     * Returns game model manager that responsible for saving and restoring game model
     * 
     * @return {@link GameModelManager}
     */
    public GameModelManager getGameModelManager() {
        return gameModelManager == null ? gameModelManager = new GameModelManager(
            preferences) : gameModelManager;
    }

    public PackDataProvider getPackDataProvider() {
        return packDataProvider == null ? packDataProvider = new AssetsPackDataProvider(this) : packDataProvider;
    }
    
    public boolean isSoundEnabled() {
        return preferences.getBoolean(SOUND_ENABLED_KEY, true);
    }
    
    public void setSoundEnabled(boolean soundEnabled) {
        preferences.edit().putBoolean(SOUND_ENABLED_KEY, soundEnabled).commit();
    }

    private class ServicesResolverImpl implements ServicesResolver {

        @Override
        public Object resolve(Class<?> serviceClass) {
            if (PuzzleApplication.class.isAssignableFrom(serviceClass)) {
                return PuzzleApplication.getInstance();
            }
            else if (CompletedManager.class.isAssignableFrom(serviceClass)) {
                return getCompletedManager();
            }
            else if (PackDataProvider.class.isAssignableFrom(serviceClass)) {
                return getPackDataProvider();
            }
            throw new IllegalArgumentException("Unknown service: " + serviceClass);
        }
    }
}
